package com.it.schoolhomeos.service.impl;

import com.it.schoolhomeos.dto.ExamGradeDTO;
import com.it.schoolhomeos.dto.StudentExamGradeDTO;
import com.it.schoolhomeos.dto.StudentGradeDTO;
import com.it.schoolhomeos.entity.ClassInfo;
import com.it.schoolhomeos.entity.Exam;
import com.it.schoolhomeos.entity.Grade;
import com.it.schoolhomeos.entity.Student;
import com.it.schoolhomeos.exception.ResourceNotFoundException;
import com.it.schoolhomeos.repository.ClassInfoRepository;
import com.it.schoolhomeos.repository.ExamRepository;
import com.it.schoolhomeos.repository.GradeRepository;
import com.it.schoolhomeos.repository.StudentRepository;
import com.it.schoolhomeos.service.GradeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import lombok.extern.slf4j.Slf4j;

/**
 * GradeService接口的实现类
 * 
 * 实现成绩相关的业务逻辑
 */
@Service
@Slf4j
@Transactional
public class GradeServiceImpl implements GradeService {

    @Autowired
    private GradeRepository gradeRepository;
    
    @Autowired
    private StudentRepository studentRepository;
    
    @Autowired
    private ClassInfoRepository classInfoRepository;
    
    @Autowired
    private ExamRepository examRepository;
    
    /**
     * 获取成绩记录列表
     * 
     * @param studentId 学生ID，可为null
     * @param subject 科目，可为null
     * @param examId 考试ID，可为null
     * @param page 页码
     * @param size 每页大小
     * @return 分页的成绩记录列表
     */
    @Override
    public Page<Grade> getGrades(Long studentId, String subject, Long examId, int page, int size) {
        Pageable pageable = PageRequest.of(page, size, Sort.by("createTime").descending());
        Student student = studentId != null ? studentRepository.findById(studentId)
                .orElseThrow(() -> new RuntimeException("学生不存在")) : null;
        
        if (student != null && subject != null && examId != null) {
            return gradeRepository.findByStudentAndSubjectAndExamId(student, subject, examId, pageable);
        } else if (student != null && subject != null) {
            return gradeRepository.findByStudentAndSubject(student, subject, pageable);
        } else if (student != null && examId != null) {
            return gradeRepository.findByStudentAndExamId(student, examId, pageable);
        } else if (subject != null && examId != null) {
            return gradeRepository.findBySubjectAndExamId(subject, examId, pageable);
        } else if (student != null) {
            return gradeRepository.findByStudent(student, pageable);
        } else if (subject != null) {
            return gradeRepository.findBySubject(subject, pageable);
        } else if (examId != null) {
            return gradeRepository.findByExamId(examId, pageable);
        }
        
        return gradeRepository.findAll(pageable);
    }
    
    /**
     * 获取指定学生的成绩记录
     * 
     * @param studentId 学生ID
     * @param subject 科目，可为null
     * @param examId 考试ID，可为null
     * @return 学生的成绩记录列表
     */
    @Override
    public List<Grade> getStudentGrades(Long studentId, String subject, Long examId) {
        Student student = studentRepository.findById(studentId)
                .orElseThrow(() -> new RuntimeException("学生不存在"));
                
        if (subject != null && examId != null) {
            return gradeRepository.findByStudentAndSubjectAndExamId(student, subject, examId);
        } else if (subject != null) {
            return gradeRepository.findByStudentAndSubject(student, subject);
        } else if (examId != null) {
            return gradeRepository.findByStudentAndExamId(student, examId);
        } else {
            return gradeRepository.findByStudent(student);
        }
    }
    
    /**
     * 根据ID获取成绩记录详情
     * 
     * @param id 成绩记录ID
     * @return 成绩记录对象
     * @throws RuntimeException 如果成绩记录不存在
     */
    @Override
    public Grade getGradeById(Long id) {
        return gradeRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("成绩记录不存在"));
    }
    
    /**
     * 创建新成绩记录
     * 
     * @param grade 成绩记录对象
     * @return 创建成功的成绩记录对象
     */
    @Override
    public Grade saveGrade(Grade grade) {
        if (grade.getId() != null) {
            throw new RuntimeException("新建成绩记录不应该包含ID");
        }
        grade.setCreateTime(LocalDateTime.now());
        grade.setUpdateTime(LocalDateTime.now());
        return gradeRepository.save(grade);
    }
    
    /**
     * 更新成绩记录
     * 
     * @param grade 成绩记录对象
     * @return 更新后的成绩记录对象
     * @throws RuntimeException 如果成绩记录不存在
     */
    @Override
    public Grade updateGrade(Grade grade) {
        if (grade.getId() == null) {
            throw new RuntimeException("更新成绩记录必须包含ID");
        }
        
        Grade existingGrade = gradeRepository.findById(grade.getId())
                .orElseThrow(() -> new RuntimeException("成绩记录不存在"));
        
        grade.setCreateTime(existingGrade.getCreateTime());
        grade.setUpdateTime(LocalDateTime.now());
        return gradeRepository.save(grade);
    }
    
    /**
     * 删除成绩记录
     * 
     * @param id 成绩记录ID
     * @throws RuntimeException 如果成绩记录不存在
     */
    @Override
    public void deleteGrade(Long id) {
        if (!gradeRepository.existsById(id)) {
            throw new RuntimeException("成绩记录不存在");
        }
        gradeRepository.deleteById(id);
    }

    @Override
    public Grade createGrade(Grade grade) {
        return saveGrade(grade);
    }

    @Override
    public List<Grade> createGrades(List<Grade> grades) {
        LocalDateTime now = LocalDateTime.now();
        grades.forEach(grade -> {
            if (grade.getId() != null) {
                throw new RuntimeException("新建成绩记录不应该包含ID");
            }
            grade.setCreateTime(now);
            grade.setUpdateTime(now);
        });
        return gradeRepository.saveAll(grades);
    }

    @Override
    public Page<Grade> getClassGrades(Long classId, String subject, Long examId, int page, int size) {
        Pageable pageable = PageRequest.of(page, size, Sort.by("examId", "subject"));
        ClassInfo classInfo = classInfoRepository.findById(classId)
                .orElseThrow(() -> new RuntimeException("班级不存在"));
                
        if (subject != null && examId != null) {
            return gradeRepository.findByClassInfoAndSubjectAndExamId(classInfo, subject, examId, pageable);
        } else if (subject != null) {
            return gradeRepository.findByClassInfoAndSubject(classInfo, subject, pageable);
        } else if (examId != null) {
            return gradeRepository.findByClassInfoAndExamId(classInfo, examId, pageable);
        } else {
            return gradeRepository.findByClassInfo(classInfo, pageable);
        }
    }
    
    /**
     * 获取考试的某个科目的所有学生成绩
     * 
     * @param examId 考试ID
     * @param subject 科目
     * @return 学生成绩列表
     */
    @Override
    public List<StudentGradeDTO> getExamSubjectGrades(Long examId, String subject) {
        // 验证考试是否存在
        Exam exam = examRepository.findById(examId)
                .orElseThrow(() -> new RuntimeException("考试不存在"));
        
        // 验证科目是否属于该考试
        List<String> subjects = exam.getSubjectList();
        if (!subjects.contains(subject)) {
            throw new RuntimeException("该考试不包含此科目");
        }
        
        // 获取该考试该科目的所有成绩记录
        List<Grade> grades = gradeRepository.findByExamIdAndSubject(examId, subject);
        
        // 将成绩记录转换为Map，方便查找
        Map<Long, Grade> gradeMap = grades.stream()
                .collect(Collectors.toMap(g -> g.getStudent().getId(), g -> g));
        
        // 获取所有学生
        List<Student> students = studentRepository.findAll();
        
        // 构建学生成绩DTO列表
        return students.stream()
                .map(student -> {
                    Grade grade = gradeMap.get(student.getId());
                    return StudentGradeDTO.builder()
                            .studentId(student.getId())
                            .studentNumber(student.getStudentNumber())
                            .name(student.getName())
                            .score(grade != null ? grade.getScore() : null)
                            .hasGrade(grade != null)
                            .build();
                })
                .collect(Collectors.toList());
    }
    
    /**
     * 获取学生在某次考试中的所有科目成绩
     * 
     * @param studentId 学生ID
     * @param examId 考试ID
     * @return 科目成绩映射
     */
    @Override
    public Map<String, Double> getStudentExamGrades(Long studentId, Long examId) {
        // 验证学生是否存在
        Student student = studentRepository.findById(studentId)
                .orElseThrow(() -> new RuntimeException("学生不存在"));
        
        // 验证考试是否存在
        Exam exam = examRepository.findById(examId)
                .orElseThrow(() -> new RuntimeException("考试不存在"));
        
        // 获取该学生在该考试中的所有成绩记录
        List<Grade> grades = gradeRepository.findByStudentIdAndExamId(studentId, examId);
        
        // 将成绩记录转换为科目-分数映射
        return grades.stream()
                .collect(Collectors.toMap(Grade::getSubject, Grade::getScore));
    }
    
    /**
     * 录入学生成绩
     * 
     * @param examId 考试ID
     * @param subject 科目
     * @param studentId 学生ID
     * @param score 分数
     * @return 成绩记录
     */
    @Override
    @Transactional
    public Grade enterGrade(Long examId, String subject, Long studentId, Double score) {
        // 获取考试信息
        Exam exam = examRepository.findById(examId)
                .orElseThrow(() -> new ResourceNotFoundException("考试不存在: " + examId));
                
        // 获取学生信息
        Student student = studentRepository.findById(studentId)
                .orElseThrow(() -> new ResourceNotFoundException("学生不存在: " + studentId));
        
        // 创建或更新成绩
        Grade grade = gradeRepository.findByStudentIdAndExamIdAndSubject(studentId, examId, subject)
                .orElse(new Grade());
        
        grade.setStudent(student);
        grade.setExamId(examId);
        grade.setExamName(exam.getName());  // 设置考试名称
        grade.setSubject(subject);
        grade.setScore(score);
        
        return gradeRepository.save(grade);
    }
    
    /**
     * 批量录入学生成绩
     * 
     * @param examId 考试ID
     * @param subject 科目
     * @param studentScores 学生成绩映射（学生ID -> 分数）
     * @return 成绩记录列表
     */
    @Override
    @Transactional
    public List<Grade> batchEnterGrades(Long examId, String subject, Map<Long, Double> studentScores) {
        // 获取考试信息
        Exam exam = examRepository.findById(examId)
                .orElseThrow(() -> new ResourceNotFoundException("考试不存在: " + examId));
        
        List<Grade> grades = new ArrayList<>();
        
        for (Map.Entry<Long, Double> entry : studentScores.entrySet()) {
            Long studentId = entry.getKey();
            Double score = entry.getValue();
            
            // 获取学生信息
            Student student = studentRepository.findById(studentId)
                    .orElseThrow(() -> new ResourceNotFoundException("学生不存在: " + studentId));
            
            // 创建或更新成绩
            Grade grade = gradeRepository.findByStudentIdAndExamIdAndSubject(studentId, examId, subject)
                    .orElse(new Grade());
            
            grade.setStudent(student);
            grade.setExamId(examId);
            grade.setExamName(exam.getName());  // 设置考试名称
            grade.setSubject(subject);
            grade.setScore(score);
            
            grades.add(grade);
        }
        
        return gradeRepository.saveAll(grades);
    }
    
    /**
     * 获取考试的所有学生成绩和排名
     * 
     * @param examId 考试ID
     * @return 学生考试成绩列表
     */
    @Override
    public List<StudentExamGradeDTO> getExamGradesWithRanking(Long examId) {
        // 验证考试是否存在
        Exam exam = examRepository.findById(examId)
                .orElseThrow(() -> new RuntimeException("考试不存在"));
        
        // 获取所有学生
        List<Student> students = studentRepository.findAll();
        
        // 获取该考试的所有成绩记录
        List<Grade> allGrades = gradeRepository.findByExamId(examId);
        
        // 按学生ID分组
        Map<Long, List<Grade>> gradesByStudent = allGrades.stream()
                .collect(Collectors.groupingBy(g -> g.getStudent().getId()));
        
        // 构建学生考试成绩DTO列表
        List<StudentExamGradeDTO> result = new ArrayList<>();
        
        for (Student student : students) {
            List<Grade> studentGrades = gradesByStudent.getOrDefault(student.getId(), Collections.emptyList());
            
            // 计算各科目成绩
            Map<String, Double> subjectScores = studentGrades.stream()
                    .collect(Collectors.toMap(Grade::getSubject, Grade::getScore));
            
            // 计算总分
            double totalScore = studentGrades.stream()
                    .mapToDouble(Grade::getScore)
                    .sum();
            
            result.add(StudentExamGradeDTO.builder()
                    .studentId(student.getId())
                    .studentNumber(student.getStudentNumber())
                    .name(student.getName())
                    .subjectScores(subjectScores)
                    .totalScore(totalScore)
                    .build());
        }
        
        // 按总分排序并设置排名
        result.sort(Comparator.comparing(StudentExamGradeDTO::getTotalScore).reversed());
        
        for (int i = 0; i < result.size(); i++) {
            result.get(i).setRanking(i + 1);
        }
        
        return result;
    }
    
    /**
     * 获取学生的历史考试成绩
     * 
     * @param studentId 学生ID
     * @return 考试成绩列表
     */
    @Override
    public List<ExamGradeDTO> getStudentHistoryGrades(Long studentId) {
        // 验证学生是否存在
        Student student = studentRepository.findById(studentId)
                .orElseThrow(() -> new RuntimeException("学生不存在"));
        
        // 获取该学生的所有成绩记录
        List<Grade> allGrades = gradeRepository.findByStudentId(studentId);
        
        // 按考试ID分组
        Map<Long, List<Grade>> gradesByExam = allGrades.stream()
                .collect(Collectors.groupingBy(Grade::getExamId));
        
        // 构建考试成绩DTO列表
        List<ExamGradeDTO> result = new ArrayList<>();
        
        for (Map.Entry<Long, List<Grade>> entry : gradesByExam.entrySet()) {
            Long examId = entry.getKey();
            List<Grade> examGrades = entry.getValue();
            
            // 获取考试信息
            Exam exam = examRepository.findById(examId)
                    .orElseThrow(() -> new RuntimeException("考试不存在: " + examId));
            
            // 计算各科目成绩
            Map<String, Double> subjectScores = examGrades.stream()
                    .collect(Collectors.toMap(Grade::getSubject, Grade::getScore));
            
            // 计算总分
            double totalScore = examGrades.stream()
                    .mapToDouble(Grade::getScore)
                    .sum();
            
            result.add(ExamGradeDTO.builder()
                    .examId(examId)
                    .examName(exam.getName())
                    .examDate(exam.getExamDate())
                    .subjectScores(subjectScores)
                    .totalScore(totalScore)
                    .build());
        }
        
        // 按考试日期排序
        result.sort(Comparator.comparing(ExamGradeDTO::getExamDate).reversed());
        
        return result;
    }
} 